<?php

namespace app\common;

use think\facade\Cache;

/**
 * Redis缓存驱动，适合单机部署、有前端代理实现高可用的场景，性能最好
 * 有需要在业务层实现读写分离、或者使用RedisCluster的需求，请使用Redisd驱动
 *
 * 要求安装phpredis扩展：https://github.com/nicolasff/phpredis
 * @author    尘缘 <130775@qq.com>
 */
class Redis
{

    /**
     * 判断缓存
     * @access public
     * @param  string $name 缓存变量名
     * @return bool
     */
    public function has($name)
    {
        return  Cache::store('redis')->handler()->exists($this->getCacheKey($name));
    }

    /**
     * 读取缓存
     * @access public
     * @param  string $name 缓存变量名
     * @param  mixed  $default 默认值
     * @return mixed
     */
    public function get($name, $default = false)
    {
        $this->readTimes++;

        $value = Cache::store('redis')->handler()->get($this->getCacheKey($name));

        if (is_null($value) || false === $value) {
            return $default;
        }

        return $this->unserialize($value);
    }

    /**
     * 写入缓存
     * @access public
     * @param  string            $name 缓存变量名
     * @param  mixed             $value  存储数据
     * @param  integer|\DateTime $expire  有效时间（秒）
     * @return boolean
     */
    public function set($name, $value, $expire = null)
    {
        $this->writeTimes++;

        if (is_null($expire)) {
            $expire = $this->options['expire'];
        }

        if ($this->tag && !$this->has($name)) {
            $first = true;
        }

        $key    = $this->getCacheKey($name);
        $expire = $this->getExpireTime($expire);

        $value = $this->serialize($value);

        if ($expire) {
            $result = Cache::store('redis')->handler()->setex($key, $expire, $value);
        } else {
            $result = Cache::store('redis')->handler()->set($key, $value);
        }

        isset($first) && $this->setTagItem($key);

        return $result;
    }

    /**
     * 自增缓存（针对数值缓存）
     * @access public
     * @param  string    $name 缓存变量名
     * @param  int       $step 步长
     * @return false|int
     */
    public function inc($name, $step = 1)
    {
        $this->writeTimes++;

        $key = $this->getCacheKey($name);

        return Cache::store('redis')->handler()->incrby($key, $step);
    }

    /**
     * 自减缓存（针对数值缓存）
     * @access public
     * @param  string    $name 缓存变量名
     * @param  int       $step 步长
     * @return false|int
     */
    public function dec($name, $step = 1)
    {
        $this->writeTimes++;

        $key = $this->getCacheKey($name);

        return Cache::store('redis')->handler()->decrby($key, $step);
    }

    /**
     * 删除缓存
     * @access public
     * @param  string $name 缓存变量名
     * @return boolean
     */
    public function rm($name)
    {
        $this->writeTimes++;

        return Cache::store('redis')->handler()->del($this->getCacheKey($name));
    }

    /**
     * 清除缓存
     * @access public
     * @param  string $tag 标签名
     * @return boolean
     */
    public function clear($tag = null)
    {
        if ($tag) {
            // 指定标签清除
            $keys = $this->getTagItem($tag);

           Cache::store('redis')->handler()->del($keys);

            $tagName = $this->getTagKey($tag);
            Cache::store('redis')->handler()->del($tagName);
            return true;
        }

        $this->writeTimes++;

        return Cache::store('redis')->handler()->flushDB();
    }

    /**
     * 缓存标签
     * @access public
     * @param  string        $name 标签名
     * @param  string|array  $keys 缓存标识
     * @param  bool          $overlay 是否覆盖
     * @return $this
     */
    public function tag($name, $keys = null, $overlay = false)
    {
        if (is_null($keys)) {
            $this->tag = $name;
        } else {
            $tagName = $this->getTagKey($name);
            if ($overlay) {
                Cache::store('redis')->handler()->del($tagName);
            }

            foreach ($keys as $key) {
				Cache::store('redis')->handler()->sAdd($tagName, $key);
            }
        }

        return $this;
    }

    /**
     * 更新标签
     * @access protected
     * @param  string $name 缓存标识
     * @return void
     */
    protected function setTagItem($name)
    {
        if ($this->tag) {
            $tagName = $this->getTagKey($this->tag);
            Cache::store('redis')->handler()->sAdd($tagName, $name);
        }
    }

    /**
     * 获取标签包含的缓存标识
     * @access protected
     * @param  string $tag 缓存标签
     * @return array
     */
    protected function getTagItem($tag)
    {
        $tagName = $this->getTagKey($tag);
        return Cache::store('redis')->handler()->sMembers($tagName);
    }
	
	/**
     * 在list左边添加一值为$value的元素
     * @access protected
     * @param  string $key 
	 * @param  string $value  
     * @return int
     */
    public function lPush($key,$value)
    {
        return Cache::store('redis')->handler()->lPush($key,$value);
    }
	
	/**
     * 获取list的长度
     * @access protected
     * @param  string $key 
     * @return int
     */
    public function lLen($key)
    {
        return Cache::store('redis')->handler()->lLen($key);
    }
	
	/**
     * 在list右边添加一值为$value的元素
     * @access protected
     * @param  string $key 
	 * @param  string $value 
     * @return int
     */
    public function rPush($key,$value)
    {
        return Cache::store('redis')->handler()->rPush($key,$value);
    }
	
	/**
     * 移出并获取列表的左边第一个元素
     * @access protected
     * @param  string $key 
     * @return string
     */
    public function lPop($key)
    {
        return Cache::store('redis')->handler()->lPop($key);
    }
	
	/**
     * 移出并获取列表的右边第一个元素
     * @access protected
     * @param  string $key 
     * @return string
     */
    public function rPop($key)
    {
        return Cache::store('redis')->handler()->rPop($key);
    }
}
